import json, datetime, asyncio, re, requests
import myURL, funcs, utility_classes

client = None  # aiohttp的client绘画。引用者提供

zhishu_symbols=['sh000001','sz399001','sz399006']
zhishu_symbols_total = ['sh000001', 'sz399001', 'sz399006', 'sh000300', 'sh000016', 'sz399005']
zhishu_news_list=[]
ggyl_dic={}
zhishuyl_columns = ['symbol', 'name', 'trade', 'open', 'high', 'low', 'change', 'changepercent', 'amplitude', 'vol', 'amount', 'qrr', 'upnum', 'flatnum', 'downnum']
zhishuyl_dic = {'columns':zhishuyl_columns}
general_infomations = {}
bkranking_dic = {}
now= lambda : datetime.datetime.now()

#async def sina_bk():
#    resText = await _get_data(myURL.url_sina_bk_ranking, funcs.format_bk_ranking)
#    return json.loads(resText)

#async def gn_bk():
#    resText = await _get_data(myURL.url_gn_bk_ranking, funcs.format_bk_ranking)
#    return json.loads(resText)

#async def zjh_bk():
#    resText = await _get_data(myURL.url_zjh_bk_ranking, funcs.format_bk_ranking)
#    return json.loads(resText)

#async def dy_bk():
#    resText = await _get_data(myURL.url_dy_bk_ranking, funcs.format_bk_ranking)
#    return json.loads(resText)



#async def sssj(symbols_str):
#    u = myurl.url_sssj + symbols_str
#    res = await _get_data(u, funcs.format_sssj)
#    return res

max_bk_items = 40
bkranking_column = ['symbol', 'name', 'companyNum', 'averagePrice', 'change', 'changepercent', 'vol', 'amount', 'top1symbol', 'top1changepercent', 'top1trade', 'top1change', 'top1name']
async def bk_ranking(bk_name, page, num = 20, desc = 0):
    d = {}
    if bk_name in bkranking_dic and num <= max_bk_items:
        bk = bkranking_dic[bk_name]
        start = (page -1) * num
        if start < len(bk):
            d['columns'] = bkranking_column
            d['total'] = len(bk)
            if desc == 0:
                d['data'] = bk[start: start + num]
            else:
                if start == 0:
                    l = bk[-num:]
                else:
                    l = bk[-start - num: -start]
                l.reverse()
                d['data'] = l
    return d



async def nodedata(node, sort, asc, page, num = 20):
    nodeUrl = myURL.url_node_data % (page, num, sort, asc, node)
    text = await client_get(nodeUrl)
    return json.loads(text)



async def get_tick(symbol):
    url = myURL.get_tick.format(symbol)
    res = await _get_data(url,funcs.format_tick)
    res['columns'] = ['trade','vol']
    return res


async def get_k_last(symbol, freq, num, adj):
    res = await _get_k(symbol, freq, num = num, adj = adj)
    return res


async def get_k(symbol, freq, adj, start, end, num = 320):
    max_num = 320
    if num > max_num:
        num = max_num
    res = await _get_k(symbol, freq, start, end, adj, num)
    return res


async def search(key):
    url = myURL.search.format(key)
    res = await client_get(url)
    res = res.replace('define','columns')
    return json.loads(res)


async def zhishuyl():
    return zhishuyl_dic


async def ggyl(keys):
    keys = keys.split(',')
    d={}
    for k in keys:
        if k in ggyl_dic:
            d[k] = ggyl_dic[k]
    return d

async def get_news_list(symbol = None, page = 1, num = 50):
    if symbol:
        url = myURL.get_news_list.format(page,symbol, num)
        listStr = await client_get(url)
        res = json.loads(listStr)
        if res['code'] == 0:
            return res['data']['data']
        return []
    return zhishu_news_list



async def get_stock_general_infomation(symbol):
    if isinstance(symbol, str) == False or len(symbol) != 8 or symbol[:2] not in general_infomations:
        return None
    else:
        symbolhead = symbol[:2]
        newsymbol = symbol[-6:] + '.' + symbolhead.upper()
        for i in general_infomations[symbolhead]['items']:
            if newsymbol == i[0]:
                d = {'columns': general_infomations[symbolhead]['fields'][1:]}
                d['data'] = i[1:]
                return d
    return None



async def _get_dataPro(t, p, num = -1):
    url = myURL.get_dataPro.format(t, p)
    res = await _get_data(url, funcs.get_jsonlist)
    return res[:num]



k_columns = ['time', 'open', 'close', 'high', 'low', 'vol']
async def _get_k(symbol,freq,start = '', end = '', adj='', num = 100):
    if re.match(r'm\d+',freq):
        url = myURL.get_k_min.format(symbol,freq,num)
    else:
        url = myURL.get_k.format(symbol,freq,start,end,num,adj);
    res = await client_get(url)
    jo = json.loads(res)
    if jo['code'] == 0:
        d = {'columns':k_columns}
        key = adj + freq
        if key in jo['data'][symbol]:
            d['data'] = jo['data'][symbol][key]
        else:
            d['data'] = jo['data'][symbol][freq]
        return d
    return None



zdf_columns = ['symbol', 'changepercent']
hs_columns = ['symbol', 'turnover']
cje_columns = ['symbol', 'amount']
zlzj_columns = ['symbol', 'zllr', 'zllc', 'jlr']
async def _update_ggyl():
    await asyncio.sleep(2)
    await _get_ggyl()
    utility_classes.print_log('first update ggyl successfully')
    while(True):
        h = now().hour
        if h > 8 and h <17:
            await _get_ggyl()
            await asyncio.sleep(6)
        else:
            await asyncio.sleep(1800)


async def _get_ggyl():
    try:
        res = await client_get(myURL.ggzlzj)
        l = res.split(';')
        ggyl_dic['zllr'] = {'columns':zlzj_columns, 'data': funcs.get_jsonlist(l[0])}
        ggyl_dic['zllc'] = {'columns':zlzj_columns, 'data': funcs.get_jsonlist(l[1])}
    except Except as e:
        utility_classes.print_log('update_zlzj', e, res)
    try:
        url = myURL.url_sssj + 'azdftop10,azdfend10,acjetop10,ahsltop10'
        res = await client_get(url)
        l = res.split(';')
        tmp = []
        for i in range(4):
            x = funcs.get_jsonlist(l[i])
            tmp.append([[funcs.create_symbol(k[3],k[4]), k[2]] for k in x if len(k) >= 5])
        ggyl_dic['zftop10'] = {'columns':zdf_columns, 'data':tmp[0]}
        ggyl_dic['dftop10'] = {'columns':zdf_columns, 'data':tmp[1]}
        ggyl_dic['cjetop10'] = {'columns':cje_columns, 'data':tmp[2]}
        ggyl_dic['hstop10'] = {'columns':hs_columns, 'data':tmp[3]}
    except Exception as e:
        utility_classes.print_log('update_top10', e, res)
    try:
        zdb = await _get_dataPro(1,5, -1)
        ggyl_dic['zf5day'] = {'columns': zdf_columns, 'data': zdb[:10]}
        ggyl_dic['df5day'] = {'columns': zdf_columns, 'data': zdb[-10:]}
        ggyl_dic['hs5day'] = {'columns':hs_columns, 'data': await _get_dataPro(4,5,10)}
        ggyl_dic['ddpx_buy'] = {'columns': hs_columns, 'data': await _get_dataPro(5,1,10)}
        ggyl_dic['ddpx_sell'] = {'columns': hs_columns, 'data': await _get_dataPro(6,1,10)}
    except Exception as e:
        utility_classes.print_log('update_pro', e)

async def _update_zhishuyl():
    await asyncio.sleep(1)
    await _get_zhishuyl()
    utility_classes.print_log('first update zhishuyl successfully')
    while(True):
        h = now().hour
        if h > 8 and h < 17:
            await _get_zhishuyl()
            await asyncio.sleep(5)
        else:
            await asyncio.sleep(1800)

async def _get_zhishuyl():
    l = []
    for k in zhishu_symbols_total:
        try:
            url = myURL.get_k.format(k,'day','','',0,'bfq')
            url2 = myURL.minute.format(k)
            res = await client_get(url)
            jo = json.loads(res)
            if jo['code'] == 0:
                info1 = jo['data'][k]['qt'][k]
                info2 = jo['data'][k]['qt'].get('zhishu')
                if not info2:
                    res = await client_get(url2)
                    jo = json.loads(res)
                    info2 = jo['data'][k]['qt'].get('zhishu')
                if info2:
                    data = [k, info1[1], info1[3], info1[5], info1[33], info1[34], info1[31], info1[32], info1[43], info1[36], info1[37], info1[49], info2[2], info2[3], info2[4]]
                else:
                    data = [k, info1[1], info1[3], info1[5], info1[33], info1[34], info1[31], info1[32], info1[43], info1[36], info1[37], info1[49], '0', '0', '0']
            else:
                continue
            l.append(data)
        except Exception as e:
            utility_classes.print_log('update_zhishu', e, k, res)
    zhishuyl_dic['data'] = l



async def _update_zhishu_news_list():
    await asyncio.sleep(3)
    while(True):
        zhishu_news_list.clear()
        for k in zhishu_symbols:
            try:
                l = await get_news_list(k, 1, 20)
                zhishu_news_list.append(l)
            except Exception as e:
                utility_classes.print_log('update_newslist', e, k)
        await asyncio.sleep(60)



async def _update_bkranking():
    await asyncio.sleep(5)
    await _get_bkranking()
    utility_classes.print_log('first update bkranking successfully')
    while(True):
        h = now().hour
        if h > 8 and h < 17:
            await _get_bkranking()
            await asyncio.sleep(5)
        else:
            await asyncio.sleep(1800)

async def _get_bkranking():
    for key, url in myURL.url_bks.items():
        try:
            dstr = await client_get(url)
            if len(dstr) > 100:
                bkranking_dic[key] = funcs.format_bk_ranking(dstr)
            else:
                utility_classes.print_log('update_bk',dstr)
        except Exception as e:
            utility_classes.print_log('update_bk', 'exception', e, 'key', key, 'returnStr', dstr)
        await asyncio.sleep(1)



async def client_get(url):
    async with client.get(url) as resp:
        if resp.status == 200:
            try:
                return await (resp.text(encoding='gbk'))
            except Exception as e:
                print('\nURL:', url)
                raise

            print('\nURL:', url, '\n:', resp.status, '\n:', await (resp.test()))
            raise Exception()

async def client_post(url, data):
    async with client.post(url, data = data) as resp:
        if resp.status == 200:
            try:
                return await (resp.text(encoding='utf-8'))
            except Exception as e:
                print('\nURL:', url)
                raise

            print('\nURL:', url, '\n:', resp.status, '\n:', await (resp.test()))
            raise


async def _get_data(url, func_method):
    try:
        jstr = await (client_get(url))
        jstr = func_method(jstr)
        return jstr
    except json.JSONDecodeError as e:
        print('json\nURL:', url)
        print(e)
    except Exception as e:
        logging.exception(e)

    return None


####################################################


tushare_token = 'ebe8a9918702d8a922b3f2f93cd4d6b9431dbf7bc278ad222468f36c'
async def _get_general_infomations(exchange):
    api_name = 'stock_company'
    fields = 'ts_code,introduction,main_business,business_scope,province,city,reg_capital,setup_date,employees,chairman,manager,email,website,office'
    url = 'http://api.tushare.pro'
    data = {'api_name':api_name, 'token':tushare_token, 'params':{'exchange': exchange}, 'fields':fields}
    r = await client_post(url, json.dumps(data))
    #r = requests.post(url, data = json.dumps(data)).text
    jo = json.loads(r)
    if jo['code'] == 0:
        return jo['data']
    return None


async def _update_general_infomations():
    await asyncio.sleep(6)
    general_infomations.clear()
    general_infomations['sh'] = await _get_general_infomations('SSE')
    general_infomations['sz'] = await _get_general_infomations('SZSE')
    s = False
    utility_classes.print_log('基本信息更新成功')
    while(True):
        if now().day == 1 and s:
            general_infomations.clear()
            general_infomations['sh'] = await _get_general_infomations('SSE')
            general_infomations['sz'] = await _get_general_infomations('SZSE')
            s = False
            utility_classes.print_log('基本信息更新成功')
        else:
            await asyncio.sleep(43200)
            if now().day != 1:
                s = True

    





######################################


def get_cron_tasks():
    return [_update_general_infomations(), _update_ggyl(), _update_zhishuyl(), _update_zhishu_news_list(), _update_bkranking()]


async def call_api(api_name, params = None):
    if params:
        r = await con[api_name](**params)
    else:
        r = await con[api_name]()
    return r


con = globals()